import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.List;
import java.util.Scanner;

import daointerfaces.DALException;
import dto.ProduktBatchDTO;
import dto.RaavareBatchDTO;

public class Main {
	static String fromServer;
	static boolean run = true;
	static Scanner input = new Scanner(System.in);
	static String ip, port, text, host;
	static WeightProtocol Protocol;
	static double taraProduct;
	static PrintStream out;
	static BufferedReader in;
	static DatabaseConnecter databaseCon;
	static String[] host2;
	static double productNetto = 0;

	static int operatorID, productBatchID;
	static String startTid;


	static Scanner consolInput = new Scanner(System.in);


	public static void main(String[] args) throws IOException {
		databaseCon = new DatabaseConnecter();
		System.out.println("Ip and port devided by :");
		host = input.nextLine();
		host2 = host.split(":");
		ip = host2[0];
		port = host2[1];
		System.out.println("Establishing connecting to weight on: "+host);

		try { 
			@SuppressWarnings("resource")
			Socket SSocket = new Socket(ip, Integer.parseInt(port));
			out = new PrintStream(SSocket.getOutputStream(), true);
			in = new BufferedReader(new InputStreamReader(SSocket.getInputStream()));

			Protocol = new WeightProtocol(out, in);

			while(run){	//keeps running for as long as the connection is kept.
				login();
				productBatchID();
				addComponents();
				removeProduct();
			}
		}
		catch (IOException e) {	//Catch if no connection could be made
			System.out.println("Could not connect to server on port: "+port);
			System.exit(-1);
		}
		catch (ArrayIndexOutOfBoundsException e){
			System.out.println("Invalid input");
		}
	}

	private static void login(){
		String tempName = null;
		boolean loggedIn = false;
		String[] inputID = {"Please input your ID Nr", "", ""};
		String[] retry = {"Invalid userID", "", ""};
		String tempOperatorID = Protocol.sendRM20(inputID);

		while(loggedIn == false){
			try{	//Checks if the operatorID is correct, atm only checks if int
				int tempOprID = Integer.parseInt(tempOperatorID);
				tempName = databaseCon.getOperator(tempOprID);
				String[] checkName = {"Name: "+tempName, "Is this you?", ""};
				String answere = Protocol.sendRM20(checkName);
				if(answere.equals("Is this you?")){
					operatorID = tempOprID;
					loggedIn = true;
				}else{
					tempOperatorID = Protocol.sendRM20(retry);
				}

			} catch (NumberFormatException e){	// Ask again
				tempOperatorID = Protocol.sendRM20(retry);
			} catch (DALException e){
				tempOperatorID = Protocol.sendRM20(retry);
			}
		}
	}

	private static void productBatchID() {	//Gets the productBatchId from the opr, and validates it.
		String[] inputProductBatchID = {"Please input pbID", "", ""};
		String[] retry = {"Invalid pbID", "", ""};
		boolean productOK = false;
		String tempProductID;

		while(!productOK){ 
			try{	//Checks if the product ID is correct, atm only checks if int
				while(!productOK){
					tempProductID = Protocol.sendRM20(inputProductBatchID);

					int tempProductBatchID = Integer.parseInt(tempProductID);

					String tempReceptName = null;
					try {
						tempReceptName = databaseCon.getProductBatchReceptName(tempProductBatchID);
					} catch (DALException e) {
						tempProductID = Protocol.sendRM20(retry);
					}

					String[] checkProduct = {"Product: " + tempReceptName, "Is this the product?", ""};

					String answere = Protocol.sendRM20(checkProduct);

					if(answere.equals("Is this the product?")){
						productBatchID = tempProductBatchID;
						productOK = true;

						//Updates all the productBatches with pbid = productBatchID to status 1, opr, starttime
						startTid = getTime();
						ProduktBatchDTO tempProductBatch = new ProduktBatchDTO(productBatchID, 0, 1, 
								operatorID, 0, 0, 0, startTid, null);
						try {
							databaseCon.updateProductBatchTimeStatusNetto(tempProductBatch);
						} catch (DALException e) {
							e.printStackTrace();
						}

						//Updates the raavareBatch lager
					}
				}
			} catch (NumberFormatException e){	// Ask again
				tempProductID = Protocol.sendRM20(retry);
			}
		}
	}

	//Gets the current sytem time as a string
	private static String getTime(){
		SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yy HH.mm.ss");
		Calendar cal = Calendar.getInstance();
		String output = sdf.format(cal.getTime());
		return output;
	}

	//Asks the user to remvove items from the weight, and then clears the weight
	private static void clearWeight() {
		String[] clearWeight = {"Please clear weight", "Press OK when done", ""};
		String answere;

		answere = Protocol.sendRM20(clearWeight);
		while( answere == null || !answere.equals("Press OK when done")){ //keeps resending until the answer is OK
			answere = Protocol.sendRM20(clearWeight);
		}
		Protocol.sendTare();
	}

	private static void addContainer() {		
		String[] addContainer = {"Please place container", "Press OK when done", ""};
		String answere;

		answere = Protocol.sendRM20(addContainer);
		while( answere == null || !answere.equals("Press OK when done")){ //keeps resending until the answer is OK
			answere = Protocol.sendRM20(addContainer);
		}

		Protocol.sendTare();
	}

	//Askes the opr to select the productBatch that they want to produce
	private static void addComponents() {
		try {
			List<ProduktBatchDTO> productBatchList = databaseCon.getProductBatchGroup(productBatchID);
			String[] inputRaavareBatchID = {"Please input a rbID", "Press OK when done", ""};
			String[] invalidInput = {"Invalid, input rbID", "Press OK when done", ""};

			while(!productBatchList.isEmpty()){
				boolean validRaavareID = false;
				int tempRaavareBatchID = 0;

				while (!validRaavareID) {
					validRaavareID = false;
					String tempRaavareBatchIDstring = Protocol.sendRM20(inputRaavareBatchID);
					tempRaavareBatchID = 0;

					try {	//Checks if the tempRaavareID is an int
						tempRaavareBatchID = Integer.parseInt(tempRaavareBatchIDstring);

						for (int k = 0; k < productBatchList.size(); k++) {
							if (productBatchList.get(k).getrbId() == tempRaavareBatchID) {
								validRaavareID = true;
								break;
							}
						}
					} catch (NumberFormatException e) {	// Ask again
						tempRaavareBatchIDstring = Protocol.sendRM20(invalidInput);
					}
				}
				if(validRaavareID){	// runs if the raavareID is an int
					//Add the next component
					addNextRaavare(productBatchList, tempRaavareBatchID);
				}
			}
		} catch (DALException e) {
			e.printStackTrace();
		}
	}

	//Aks the opr to add all the individual components, which are to be weighted.
	private static void addNextRaavare(List<ProduktBatchDTO> productBatchList, int tempRaavareBatchID) throws DALException{
		ProduktBatchDTO tempProductBatchRaavare = null;
		RaavareBatchDTO tempRaavareBatch = null;

		for(int i=0; i< productBatchList.size(); i++){
			if(productBatchList.get(i).getrbId()==tempRaavareBatchID){ // Runs if the raavareBatch is found in the productBatch
				addContainer();
				tempProductBatchRaavare = productBatchList.get(i);
				productBatchList.remove(i);
				String nettoProductString = null;
//				String[] addToContainer = {"Add "+tempProductBatchRaavare.getrbId(), "Press OK when done", ""};

				boolean tolOK = false;
				while(!tolOK){	// Checks if the tolerance is withing limits
					//Debug runs on the weightSim
//					String answere = Protocol.sendRM20(addToContainer);
//					while( answere == null || !answere.equals("1")){ //keeps resending until the answer is OK
//						answere = Protocol.sendRM20(addToContainer);
//					}
					
					
//					Production runs on the real weight terminal
					String[] tempRM30 = {"ok", "", "", ""};
					Protocol.sendRM30(tempRM30);
					String answere = Protocol.waitForButton();
					while( answere == null || !answere.equals("1")){	//keeps resending until the answer is OK
					}

					nettoProductString = Protocol.sendRead();
					taraProduct = Double.parseDouble(nettoProductString.split(" kg")[0]);
					int tempReceptID = tempProductBatchRaavare.getReceptId();
					tempRaavareBatch = databaseCon.getRaavareBatchDTO(tempProductBatchRaavare.getrbId());
					int raavareID = tempRaavareBatch.getRaavareId();
					double receptRaavareNetto = databaseCon.getNomNetto(tempReceptID, raavareID);		
					double raavareTol = databaseCon.getReceptRaavareTol(tempReceptID, raavareID); //Tol in %
					double raavareTolMax = receptRaavareNetto*(1+(raavareTol/100)); //Max netto
					double raavareTolMin = receptRaavareNetto*(1-(raavareTol/100)); //Min netto
//					String[] notWithinTol = {"tol err "+Math.floor(raavareTolMin)+","+Math.floor(raavareTolMax)+" ", "Press OK when done", ""};
					if(taraProduct <= raavareTolMax && taraProduct >= raavareTolMin){ //Checks if within limit
						tolOK = true;
						tempProductBatchRaavare.settera(taraProduct);
						databaseCon.updateProductBatch(tempProductBatchRaavare);
						double oldMaengde = tempRaavareBatch.getMaengde();
						tempRaavareBatch.setMaengde(oldMaengde-taraProduct);
						databaseCon.updateRaavareBatch(tempRaavareBatch);
						productNetto+=taraProduct;
					}else{
//						Protocol.sendRM20(notWithinTol);
						System.out.println("DEBUG: TolMax: "+raavareTolMax+" TolMin: "+raavareTolMin+" Tara: "+taraProduct+
								" Tolerance%: "+raavareTol);
					}
				}
				clearWeight();
			}
		}
	}

	//Asks the user to remove the product, and updates the slutTid in the database.
	private static void removeProduct() {
		String[] removeProduct = {"Please remove product", "Press OK when done", ""};
		String answere = Protocol.sendRM20(removeProduct);
		while( answere == null || !answere.equals("Press OK when done")){ //keeps resending until the answer is OK
			answere = Protocol.sendRM20(removeProduct);
		}
		Protocol.sendTare();

		//Updates all the productBatches with pbid = productBatchID to status 1, opr, starttime		
		ProduktBatchDTO tempProductBatch = 
				new ProduktBatchDTO(productBatchID, 0, 2, operatorID, 0, 0, productNetto, startTid, getTime());
		try {
			databaseCon.updateProductBatchTimeStatusNetto(tempProductBatch);
		} catch (DALException e) {
			e.printStackTrace();
		}
	}
}